/*
 * pforward.cpp
 *
 *  Created on: 2013-6-5
 *      Author: dylan
 */


#include <iostream>
#include "forwardchannel.h"
#include "tcpserver.h"
#include "udpdevice.h"
#include "comdevice.h"
#include "iodevice.h"
#include "ioaddress.h"
#include <unistd.h>
#include "../../../string_old/inc/u_args.h"

using namespace std;

void showHelp( const char* cmd ){
	cout <<" Channel Forward Tool. \n Usage:\n"
			<<cmd<<" -l local_address -r remote_address -m max_connection -t timeout\n"
			<<" address as following:\n"
			<<"\tTCP:192.168.1.177:5000\n"
			<<"\tUDP:192.168.1.177:5000\n"
			<<"\tCOM:/dev/ttyS1:9600:cs:sb\n"
			<<"\t\tcs: check mode 0,none;1,odd;2,even\n"
			<<"\t\tsb: stop bit 0,none;1,one bit\n"
			<<endl;
}

int main( int argc,char* argv[] ){
	if( argc<5 ){
		showHelp(argv[0]);
		return 0;
	}

	if( NUString::checkOpt(argc,argv,"-h") || NUString::checkOpt(argc,argv,"-help") ){
		showHelp(argv[0]);
		return 0;
	}

	CIoAddress lAddr;
	CIoAddress rAddr;

	const char* addr = NUString::getOptValue(argc,argv,"-l",NULL);
	if( addr==NULL ){
		cout <<"Please special local address with -l option.\n";
		showHelp(argv[0]);
		return 1;
	}

	lAddr = addr;
	if( lAddr.type()==CIoAddress::EIO_Unknow ){
		cout <<"Please special a correct local address with -l option.\n";
		showHelp(argv[0]);
		return 1;
	}

	addr = NUString::getOptValue(argc,argv,"-r",NULL);
	if( addr==NULL ){
		cout <<"Please special local address with -l option.\n";
		showHelp(argv[0]);
		return 1;
	}

	if( addr==NULL ){
		cout <<"Please special remote address with -r option.\n";
		showHelp(argv[0]);
		return 1;
	}

	rAddr = addr;
	if( rAddr.type()==CIoAddress::EIO_Unknow ){
		cout <<"Please special a correct remote address with -r option.\n";
		showHelp(argv[0]);
		return 1;
	}

	int timeout = 60;
	addr = NUString::getOptValue(argc,argv,"-t",NULL);
	if( addr!=NULL )
		timeout = atoi(addr);

	int limit = 1;
	addr = NUString::getOptValue(argc,argv,"-m",NULL);
	if( addr!=NULL )
		limit = atoi(addr);

	if( lAddr.type()==CIoAddress::EIO_Tcp ){
		// tcp服务器端
		CTcpServer server;
		if( !server.listenPort(lAddr.host(),lAddr.port(),limit) ){
			cout <<"can not listen to  port "<<lAddr.host()<<":"<<lAddr.port()<<endl;
			return 0;
		}

		CForwardChannel* pool = new CForwardChannel[limit];
		for( int i=0;i<limit;i++ ){
			pool[i].setOutcomeAddr(rAddr);
			pool[i].setTimeout(timeout);
		}

		char host[56];
		unsigned short port;

		while( true ){
			int p = 0;
			for( ;p<limit;p++ ){
				if( !pool[p].ifStart() )
					break;
			}

			if( p==limit ){
				sleep(1);
				continue;
			}

			CIoDevice* cli = server.acceptConnection(host,&port);
			if( cli!=NULL ){
				cout <<"get an new connection "<<host<<" :"<<port<<endl;
				pool[p].setIncome(cli);
				pool[p].start();
			}
		}
	}else{
		CForwardChannel fwc;
		fwc.setOutcomeAddr(rAddr);
		fwc.setTimeout(timeout);

		if( lAddr.type()==CIoAddress::EIO_Udp ){
			CUdpDevice* udp = new CUdpDevice;
			udp->openDevice(lAddr.host(),lAddr.port());
			fwc.setIncome(udp);
		}else if( lAddr.type()==CIoAddress::EIO_Com ){
			CComDevice* com = new CComDevice;
			com->openDevice(lAddr.device());
			com->setOpt(lAddr.bps(),8,lAddr.cs(),lAddr.stopBit());
			fwc.setIncome(com);
		}

		while( true ){
			if( fwc.ifStart() ){
				sleep(1);
				continue;
			}

			fwc.start();
		}
	}

	return 0;
}
